package cn.yangliu.oauth2.config.components;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.token.store.redis.StandardStringSerializationStrategy;

import java.util.*;

/**
 * @author 杨柳
 * @date 2019-04-19
 */
public class StringSerializationStrategy extends StandardStringSerializationStrategy {

    private Class<? extends UserDetails> userDetailClazz;

    public StringSerializationStrategy(Class<? extends UserDetails> userDetailClazz) {
        this.userDetailClazz = userDetailClazz;
    }

    @Override
    protected <T> T deserializeInternal(byte[] bytes, Class<T> clazz) {
        if (bytes == null) {
            return null;
        }
        JSONObject object = JSON.parseObject(new String(bytes));

        if (clazz.equals(OAuth2AccessToken.class)) {
            DefaultOAuth2AccessToken accessToken = JSON.parseObject(bytes, DefaultOAuth2AccessToken.class);
            String refreshTokenContent = object.getString("refreshToken");
            if (Objects.nonNull(refreshTokenContent)) {
                object = JSON.parseObject(refreshTokenContent);
                DefaultOAuth2RefreshToken refreshToken = new DefaultOAuth2RefreshToken(object.getString("value"));
                accessToken.setRefreshToken(refreshToken);
            }

            return (T) accessToken;
        } else if (clazz.equals(OAuth2Authentication.class)) {

            String userAuthenticationContent = object.getString("userAuthentication");
            JSONObject userAuthentication = JSON.parseObject(userAuthenticationContent);
            String principalContent = userAuthentication.getString("principal");
            UserDetails principal = JSON.parseObject(principalContent, userDetailClazz);

            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(principal, null, null);
            String detailsContent = userAuthentication.getString("details");
            HashMap<String, String> details = JSON.parseObject(detailsContent, HashMap.class);

            String clientId = details.get("client_id");

            Set<String> scopes = new HashSet<>();
            scopes.add(details.get("scope"));

            Collection<? extends GrantedAuthority> authorities = principal.getAuthorities();
            OAuth2Request request = new OAuth2Request(details, clientId, authorities, true, scopes, null, null, null, null);

            OAuth2Authentication auth2Authentication = new OAuth2Authentication(request, token);
            auth2Authentication.setAuthenticated(true);

            return (T) auth2Authentication;
        }
        return null;

    }

    @Override
    protected byte[] serializeInternal(Object object) {
        return JSON.toJSONBytes(object, SerializerFeature.IgnoreNonFieldGetter);
    }
}
